package hustlas.ball.preparse;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
import java.util.regex.Pattern;

/**
 * Takes a grammar as a string and converts it into a parsing table
 * 
 * @author Steven
 *
 */
public class GrammarGen {
	//TODO make a way to parse the grammar file into a parsing table
	/*TODO so basically make something that can parse the whole grammar
	 * but you can selectively choose the start state and the non-end 
	 * states and stuff KEEP IN MIND THIS IS AN LL(1) PARSE TABLE
	 */
	
	/** This is an arraylist of rules, after construction.
	 *  it should have the start rule at index zero
	 */
	private ArrayList<ParseRule> parseList;
	
	private static final String RULE_SPLITTER = "(:| )+";
	
	private Pattern ruleParser;
	
	
	public GrammarGen(String start, String rules) {
		String[] line;
		String[] tempSA;
		ArrayList<String> tempRules;
		int rulesIndex = 0;
		ParseRule temp;
		
		parseList = new ArrayList<ParseRule>();
		
		Scanner scan = new Scanner(rules);
		ruleParser = Pattern.compile(RULE_SPLITTER);
		while(scan.hasNextLine()) {
			line = ruleParser.split(scan.nextLine());
		    tempRules = new ArrayList<String>();
		    tempRules.add("");
		    rulesIndex = 0;
			
		    for(int i = 1; i < line.length; i++) {
				if(!line[i].equals("|")) {
					tempRules.set(rulesIndex,tempRules.get(rulesIndex) + line[i] + " ");
				}
				else {
					tempRules.set(rulesIndex, tempRules.get(rulesIndex).trim());
					rulesIndex++;
					tempRules.add("");
				}
			}
		    
		    tempRules.set(rulesIndex, tempRules.get(rulesIndex).trim());
		    
		    tempSA = new String[tempRules.size()];
		    tempSA = tempRules.toArray(tempSA);
		    parseList.add(new ParseRule(line[0], tempSA));
   
		}
		
		for(int i = 0; i < parseList.size(); i++) {
			if(parseList.get(i).getName().equals(start)) {
				if(i == 0) { break; }
				else {
					temp = parseList.get(i);
					parseList.set(i, parseList.get(0));
					parseList.set(0, temp);
				}
			}
		}
	}
	
	//TODO: Implement the left recursion elimination algorithm 
	public void removeLeftRecursion() {
		ArrayList<ParseRule> newRules = new ArrayList<ParseRule>();
		ArrayList<String> rulesEditor = new ArrayList<String>();
		ParseRule testRule;
		String[] ruleAddBack;
		
	    /* make a check for any left recursion once you make the first pass */ 
		for(int i = 0; i < parseList.size(); i++) {
			testRule = parseList.get(i).removeImmLeftRecursion();
			if(!testRule.equals(parseList.get(i))) {
				for(int j = i; j < parseList.size(); j++) {
					rulesEditor.addAll(Arrays.asList(parseList.get(j).getRules()));
					for(int k = 0; k < rulesEditor.size(); k++) {
						//System.out.println(rulesEditor.get(k));
						if(rulesEditor.get(k).contains(parseList.get(i).getName())) {
							for(int l = 0; l < parseList.get(i).getRules().length; l++){
								rulesEditor.add(rulesEditor.get(k).replace(
								parseList.get(i).getName(),parseList.get(i).getRules()[l]));
							}
							rulesEditor.remove(k);
						}
					}
					ruleAddBack = new String[rulesEditor.size()];
					rulesEditor.toArray(ruleAddBack);
					parseList.get(j).refactorRules(ruleAddBack);
					rulesEditor.clear();
				}
				newRules.add(testRule);
			}
		}
		parseList.addAll(newRules);
	}

	
	//TODO: make up my mind about how a parse table should be handled like a hashmap or what
	@Override
	public String toString() {
		String retStr = new String();
		for(ParseRule r : parseList) {
			retStr += r.getName() + "\n";
			for(String s : r.getRules()){
				retStr += "\t" + s + "\n";
			}
		}
		return retStr;
	}
	
	public ArrayList<ParseRule> getParseList() {
		return parseList;
	}
	
}
